#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import glob
import traceback
from .utils.log import logger


class Module:
    def __init__(self, name, entry_point, module, obj):
        self.name = name
        self.entry_point = entry_point
        self.module = module
        self.obj = obj
        if hasattr(module, 'priority'):
            self.priority = module.priority
        else:
            self.priority = 1000


class ModuleManager(object):
    def __init__(self, namespace):
        """
        init module
        """
        logger.debug("%s __init__" % self.__class__.__name__)
        basedir = os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            'modules',
            namespace.replace('.', os.path.sep))
        if basedir not in sys.path:
            sys.path.append(basedir)
        logger.debug(basedir)
        self.modules = []
        for m in glob.glob(os.path.join(basedir, '*.py')):
            if '__init__' in m:
                continue
            module_name = os.path.basename(m)
            module_name = module_name[0:module_name.find('.')]
            logger.debug('from modules.{0}.{1} import {1}'.format(
                namespace, module_name))
            rv = __import__(
                "modules.{0}.{1}".format(namespace, module_name),
                fromlist=[module_name])
            logger.debug(dir(rv))
            cl = eval('rv.{}'.format(module_name))
            if cl.priority < 0:
                # skip the module if priority < 0
                continue
            ext = Module(
                module_name.lower(),
                'modules.{}.{}'.format(namespace, module_name),
                cl, cl())
            self.modules.append(ext)
        # run modules by the priority
        self.modules.sort(key=lambda x: x.priority)

    def __getitem__(self, name):
        logger.debug("%s __getitem__" % self.__class__.__name__)
        for ext in self.modules:
            if ext.name == name:
                return ext
        raise KeyError(name)

    def __iter__(self):
        return iter(self.modules)

    def map_method(self, method_name, *argv):
        for ext in self.modules:
            try:
                if hasattr(ext.obj, method_name):
                    method = getattr(ext.obj, method_name)
                    logger.debug(
                        "Package {} method {}".format(
                            ext.entry_point, method_name))
                    method(*argv)
            except SystemExit:
                raise
            except KeyboardInterrupt:
                raise
            except Exception as e:
                logger.error(e)
                logger.debug(
                    "run method {} error in {}". format(
                        method_name, ext.name))
                raise BaseException("{}\n{}".format(e, traceback.format_exc()))
